home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
DBPCXL15.ARJ
/
SRC_C.ARJ
/
PCX.C
next >
Wrap
C/C++ Source or Header
|
1992-01-26
|
15KB
|
446 lines
/* pcxlib.c : A .PCX file decoder */
#define PCX_LIB
#include <stdio.h>
#include <io.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <alloc.h>
#include <mem.h>
#include <dos.h>
#include <errno.h>
#include "pcxlib.h"
char PCX16defpalette[16][3] = { { 0, 0, 0 },
{ 0, 0, 0x80 }, { 0, 0x80, 0 }, { 0, 0x80, 0x80 },
{ 0x80, 0, 0 }, { 0x80, 0, 0x80 }, { 0x80, 0x80, 0 },
{ 0x80, 0x80, 0x80 }, { 0xc0, 0xc0, 0xc0 }, { 0, 0, 0xff },
{ 0, 0xff, 0 }, { 0, 0xff, 0xff }, { 0xff, 0, 0 },
{ 0xff, 0, 0xff }, { 0xff, 0xff, 0 }, { 0xff, 0xff, 0xff } };
/****************************************************************************
// (PCXF *)fp=fopenPCXr("example.pcx");
//
// returns NULL on error
// reads the header and palette into fp->h and fp->palette
// sets first mark [0] to the start of scan lines
// leaves ftell at the first scan line (line 0)
//
****************************************************************************/
PCXF * fopenPCXr (char *pathname)
{
PCXF *pcxfile;
int i;
if (pcxdebug) {
fprintf(pcxdebug,"fopenPCXr(%s)\n", pathname);
}
/* malloc memory for the PCXF, PCXH, and palette structures all at
once. */
if ( !(pcxfile=(PCXF *)
malloc( sizeof(PCXF) + sizeof(PCXH) + 768) ) ) {
PCXerror=ENOMEM; return(NULL);
}
pcxfile->h=NULL;
if ((pcxfile->fp=fopen(pathname, "rb")) == NULL) {
PCXerror=ENOPATH; fclosePCX(pcxfile); return(NULL);
}
pcxfile->read_or_write=0; /* readonly */
pcxfile->h=(PCXH *)((char *)pcxfile + sizeof(PCXF));
pcxfile->name=pathname;
/* read header from file */
if (fread(pcxfile->h,sizeof(PCXH),1,pcxfile->fp) != 1){
PCXerror=errno; fclosePCX(pcxfile); return (NULL);
}
if(pcxfile->h->MagicId != 0x0a) {
fclosePCX(pcxfile); PCXerror=EINVFMT; return (NULL);
}
pcxfile->w = pcxfile->h->Xmax - pcxfile->h->Xmin + 1;
pcxfile->l = pcxfile->h->Ymax - pcxfile->h->Ymin + 1;
pcxfile->type=-1;
/* set up marks : mark 0 is scan 16 */
pcxfile->num_marks=pcxfile->l/16;
pcxfile->marks=(long *)malloc( sizeof(long)*pcxfile->num_marks);
for (i=0; i<pcxfile->num_marks; i++) {
*(pcxfile->marks + i)=0L;
}
/* Determine PCX file type */
/* 256-color file */
if (pcxfile->h->BitsPixel == 8 && pcxfile->h->Planes == 1) {
pcxfile->type=PCX256colors;
pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
pcxfile->image_size = (long) pcxfile->h->bytesline * pcxfile->l;
pcxfile->palette=(char *)((char *)pcxfile->h + sizeof(PCXH));
_read_palette(pcxfile);
} else
/* 16-color file */
if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 4) {
pcxfile->h->bytesline = ALIGN_DWORD( (pcxfile->w+1)/2 );
pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
pcxfile->type= PCX16colors;
} else
/* monochrome file */
if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 1) {
pcxfile->type=PCXMONO;
pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
} else {
if (pcxdebug) fprintf(pcxdebug,"invfmt: unknown type.\n");
PCXerror=EINVFMT;
}
if ( (pcxfile->buffer=(unsigned char *)
malloc( pcxfile->h->bytesline * 16 ) ) == NULL){
PCXerror=ENOMEM; return(NULL);
}
pcxfile->next_scan=pcxfile->buffer_scan=-1;
fseekPCX(pcxfile,0);
if (pcxdebug) {
fprintf(pcxdebug,
"p->h->bytesline=%u, p->l=%u, p->w=%u, p->type=%u\n",
pcxfile->h->bytesline, pcxfile->l, pcxfile->w, pcxfile->type);
fprintf(pcxdebug, "p=%Fp, p->h=%Fp, p->palette=%Fp\n",
pcxfile, pcxfile->h, pcxfile->palette);
}
return ((!PCXerror) ? pcxfile : NULL);
}
/*///////////////////////////////////////////////////////////////////////////
// (PCXF *)fp=fopenPCXw("example.pcx", (PCXH *)h, (char *)palette);
//
// returns NULL on error
// opens the file in mode "wb" and writes the header,
// leaving ftell at the first scan line (end-of-file).
// _write_pcx_line() should be used sequentially to write the
// data into the file, followed by _write_pcx_palette(), then
// fclosePCX().
///////////////////////////////////////////////////////////////////////////*/
PCXF * fopenPCXw(char *name, PCXH *h, char *palette)
{
PCXF *pcxfile;
if (pcxdebug) {
fprintf(pcxdebug,"fopenPCXw(%s,%Fp,%Fp)\n", name,h,palette);
}
/* malloc memory for the PCXF, PCXH, and palette structures all at
once. */
if ( !(pcxfile=(PCXF *)
malloc( sizeof(PCXF) + sizeof(PCXH) + 768 + h->bytesline) ) ) {
PCXerror=ENOMEM; return(NULL);
}
pcxfile->marks=NULL; pcxfile->num_marks=0; /* writing doesn't use marks */
pcxfile->palette=NULL;
if ((pcxfile->fp=fopen(name, "wb")) == NULL) {
PCXerror=ENOPATH; fclosePCX(pcxfile); return(NULL);
}
pcxfile->read_or_write=1; /* write only */
pcxfile->h=(PCXH *)((char *)pcxfile + sizeof(PCXF));
memcpy(pcxfile->h,h,sizeof(PCXH)); /* copy prepared header */
pcxfile->name=name;
/* write header to file */
if (fwrite(pcxfile->h,sizeof(PCXH),1,pcxfile->fp) != 1){
PCXerror=errno; fclosePCX(pcxfile); return (NULL);
}
pcxfile->w = pcxfile->h->Xmax - pcxfile->h->Xmin + 1;
pcxfile->l = pcxfile->h->Ymax - pcxfile->h->Ymin + 1;
pcxfile->type=-1;
/* Determine PCX file type */
/* 256-color file */
if (pcxfile->h->BitsPixel == 8 && pcxfile->h->Planes == 1) {
pcxfile->type=PCX256colors;
pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
pcxfile->image_size = (long) pcxfile->h->bytesline * pcxfile->l;
pcxfile->palette=(char *)((char *)pcxfile->h + sizeof(PCXH));
memcpy(pcxfile->palette,palette,768);
/* copy prepared palette */
if (pcxdebug) {
fprintf(pcxdebug,"copied palette=%Fp to ->palette=%Fp.\n",
palette, pcxfile->palette);
if ( memcmp(pcxfile->palette,palette,768) != 0)
fprintf(pcxdebug,"palette comparison failed.\n");
}
} else
/* 16-color file */
if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 4) {
pcxfile->h->bytesline = ALIGN_DWORD( (pcxfile->w+1)/2 );
pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
pcxfile->type= PCX16colors;
} else
/* monochrome file */
if (pcxfile->h->BitsPixel == 1 && pcxfile->h->Planes == 1) {
pcxfile->type=PCXMONO;
pcxfile->h->bytesline = ALIGN_DWORD(pcxfile->h->bytesline);
pcxfile->image_size = pcxfile->h->bytesline * pcxfile->l;
} else
PCXerror=EINVFMT;
pcxfile->buffer=NULL; pcxfile->next_scan=pcxfile->buffer_scan=-1;
fseekPCX(pcxfile,0);
if (pcxdebug) {
fprintf(pcxdebug,
"p->h->bytesline=%u, p->l=%u, p->w=%u, p->type=%u\n",
pcxfile->h->bytesline, pcxfile->l, pcxfile->w, pcxfile->type);
fprintf(pcxdebug, "p=%Fp, p->h=%Fp, p->palette=%Fp\n",
pcxfile, pcxfile->h, pcxfile->palette);
}
return ((!PCXerror) ? pcxfile : NULL);
}
/*///////////////////////////////////////////////////////////////////////////
// _read_pcx_line
// returns number of characters written to linebuffer
///////////////////////////////////////////////////////////////////////////*/
unsigned _read_pcx_line(PCXF *p, char * linebuffer,
unsigned x0, unsigned x1)
{
unsigned int n, w;
unsigned short run_len;
int Data;
/* n= file ptr, w=image ptr */
for (w=0,n=0; n < p->h->bytesline ; ) {
if ((Data=fgetc(p->fp)) == EOF) {
p->next_scan=-1;
return(n);
}
/* If the two high bits are set... */
if ((unsigned char)Data >= 0xc0) {
/* Get duplication count from lower bits */
run_len = (char)Data & 0x3f;
/* Set run_len bytes */
if ((Data=fgetc(p->fp)) == EOF) {
p->next_scan=-1;
return(w);
}
while(run_len--) {
if ( ((n >= x0) && (n <= x1)) )
linebuffer[w++]=(char)Data;
n++;
}
} else {
if ( ((n >= x0) && (n <= x1)) )
linebuffer[w++]=(char)Data;
n++;
}
}
p->next_scan++;
return (w);
}
/*///////////////////////////////////////////////////////////////////////////
// _write_pcx_line
// returns number of characters written to linebuffer
///////////////////////////////////////////////////////////////////////////*/
unsigned _write_pcx_line(PCXF *p, char * linebuffer,
unsigned x0, unsigned x1, unsigned char fill)
{
unsigned int n=0, w=0;
unsigned char run_len, last, data;
/* n= linebuffer, w=image offsets */
while (w < x0 ) {
if ( (x0 - w) > 63 )
run_len=63;
else
run_len=(x0-w);
if ( (run_len != 1) || (fill > 191) ) {
fputc( ( run_len | 0xc0 ),p->fp);
}
fputc(fill,p->fp);
w+=run_len;
}
run_len=1;
last=*(linebuffer+n); /* assign the first character */
w++;
for (n=1; (w < p->h->bytesline)&&(w <= x1); n++,w++) {
if ( (data=*(linebuffer+n)) == last) {
run_len++;
if ( run_len < 63 )
continue;
}
while (run_len) {
if ( (run_len != 1) || (last > 0xbf) ) {
fputc( (run_len | 0xc0),p->fp);
}
fputc(last,p->fp);
run_len=0;
}
last=data;
run_len=1;
}
/* left-overs */
while (run_len) {
if ( (run_len != 1) || (last > 0xbf) ) {
fputc( (run_len | 0xc0),p->fp);
}
fputc(last,p->fp);
run_len=0;
}
while ( w < p->h->bytesline ) {
if ( (p->h->bytesline -1 -w) < 63)
run_len= (p->h->bytesline -1 -w);
else
run_len=63;
if ( (run_len != 1) || (fill > 191) )
fputc( (run_len | 0xc0),p->fp);
fputc(fill,p->fp);
w+=run_len;
}
p->next_scan++;
return (w);
}
/*/////////////////////////////////////////////////////////////////////////
// int =fseekPCX(PCXF *pcxfile, unsigned y)
// -1 on error
///////////////////////////////////////////////////////////////////////////*/
int fseekPCX(PCXF *pcxfile, unsigned y)
{
int i=0;
long lastm=128L;
if (pcxdebug) {
fprintf(pcxdebug,"fseekPCX(%Fp, %u).\n", pcxfile, y);
}
if (y == pcxfile->next_scan) {
return(y);
}
if (y < 16) { /* home */
if (fseek(pcxfile->fp, (long)sizeof(PCXH), SEEK_SET) != 0) {
pcxfile->next_scan=-1;
return(-1);
}
pcxfile->next_scan=0;
if (y==0)
return(0);
}
if ( y>15) {
if (pcxfile->num_marks > 0) {
while ( (i<y) && (*(pcxfile->marks + (i/16-1)) != 0L) ) {
lastm=*(pcxfile->marks + (i/16-1));
i+=16;
}
if (i>15) i-=16;
if (fseek(pcxfile->fp, lastm, SEEK_SET) != 0) {
i=0;
if (fseek(pcxfile->fp, (long)sizeof(PCXH), SEEK_SET) != 0)
return(-1);
}
pcxfile->next_scan=i;
}
}
for (; i<y; i++) {
if ( ((i%16) == 0) && (i > 15)) {
*(pcxfile->marks + (i/16-1))=ftell(pcxfile->fp);
}
_read_pcx_line(pcxfile, NULL, 1, 0);
}
if ( ((i%16) == 0) && (i > 15))
*(pcxfile->marks + (i/16-1))=ftell(pcxfile->fp);
return(y);
}
/****************************************************************************
// fclosePCX
****************************************************************************/
int fclosePCX(PCXF *pcx)
{
if (pcx->marks) free(pcx->marks);
if (pcx->buffer) free(pcx->buffer);
if (pcx->fp) fclose(pcx->fp);
if (pcx) free(pcx);
return(0);
}
/*
///////////////////////////////////////////////////////////////////////////
// Palette entries have values from 0 to ff. Unfortunately, the VGA
// BIOS only uses the least significant 6 bits (i.e. values 0 - 3f).
// To adjust, right shift every entry by 2 bits ( divide by 4).
///////////////////////////////////////////////////////////////////////////
*/
void _read_palette(PCXF *p)
{
int i;
char Id256Pal;
char *pal;
/* Look for the palette at the end of the file */
if (fseek(p->fp, -769, SEEK_END) == -1) {
PCXerror=errno; return;
}
else {
/* It should start with a 0Ch byte */
if (!((fread(&Id256Pal,1,1,p->fp) == 1) && (Id256Pal == '\x0c'))) {
if (pcxdebug) fprintf(pcxdebug,"palette doesn't start with 0ch.\n");
PCXerror=EINVFMT; return;
}
else
if (fread(p->palette, 768, 1, p->fp) != 1) {
PCXerror=errno; return;
}
else {
pal=(char *)p->palette;
for (i=0; i<256; i++) {
*(pal+i*3) /=4; *(pal+i*3+1) /=4; *(pal+i*3+2) /=4;
}
}
}
return;
}
void _write_pcx_palette(PCXF *p)
{
char I256Pal=0x0c;
unsigned char *tp,*pp;
int i;
if (fwrite(&I256Pal, 1, 1, p->fp) != 1)
PCXerror=errno;
else {
if ( (tp=(unsigned char *)malloc(768)) == NULL) {
PCXerror=ENOMEM;
return;
}
pp=p->palette;
for (i=0; i<256; i++) {
*(tp+i*3) = *(pp+i*3) * 4;
*(tp+i*3+1) = *(pp+i*3+1) *4;
*(tp+i*3+2) = *(pp+i*3+2) *4;
}
if (fwrite(tp, 768, 1, p->fp) != 1)
PCXerror=errno;
}
return;
}
void Start_pcxdebug(char *path)
{
if (debugtimeson)
pcxdebug=fopen(path,"a");
else
pcxdebug=fopen(path,"w");
debugtimeson++;
}
void Close_pcxdebug(void)
{
fclose(pcxdebug);
}
int Puts_pcxdebug(char *string)
{
return(fputs(string,pcxdebug));
}